package com.nineclock.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nineclock.common.entity.PageResult;
import com.nineclock.common.entity.Result;
import com.nineclock.common.enums.ResponseEnum;
import com.nineclock.common.exception.NcException;
import com.nineclock.common.threadlocal.CurrentUserHolder;
import com.nineclock.common.utils.BeanHelper;
import com.nineclock.system.dto.SysCompanyUserDTO;
import com.nineclock.system.dto.SysDepartmentDTO;
import com.nineclock.system.dto.SysRoleDTO;
import com.nineclock.system.excel.ExcelMember;
import com.nineclock.system.excel.ExcelMemberListener;
import com.nineclock.system.mapper.*;
import com.nineclock.system.pojo.*;
import com.nineclock.system.service.SysCompanyUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@Transactional
@Slf4j
public class SysCompanyUserServiceImpl implements SysCompanyUserService {
    @Autowired
    private SysCompanyUserMapper companyUserMapper;
    @Autowired
    private SysRoleMapper roleMapper;

    @Autowired
    private SysDepartmentMapper departmentMapper;

    @Autowired
    private SysUserMapper userMapper;
    @Autowired
    private SysCompanyUserRoleMapper companyUserRoleMapper;

    /**
     * 根据传递用户ID/企业ID查询 企业员工信息
     *
     * @param userId
     * @param companyId
     * @return
     */
    @Override
    public List<SysCompanyUserDTO> queryCompanyUser(Long userId, Long companyId) {
        //1.校验参数
        //userId 用户ID , companyId 企业ID 两个必须有一个值
        if (userId == null && companyId == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //2.组装查询条件
        LambdaQueryWrapper<SysCompanyUser> companyUserWrapper = new LambdaQueryWrapper<>();
        //userId companyId 动态的
        if (userId != null) {
            companyUserWrapper.eq(SysCompanyUser::getUserId, userId);
        }
        if (companyId != null) {
            companyUserWrapper.eq(SysCompanyUser::getCompanyId, companyId);
        }

        //3.执行查询
        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(companyUserWrapper);

        //4.组装结果返回
        List<SysCompanyUserDTO> companyUserDTOS = BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);
        //如果查询到的员工集合为空 , 则抛出异常, 因为用户必须加入企业才能够登录访问
        if (CollectionUtil.isEmpty(companyUserList)) {
            throw new NcException(ResponseEnum.USER_NOT_JOIN_COMPANY);
        }

        //查询并封装 ---------------员工角色信息
        //遍历员工
        companyUserDTOS.forEach(sysCompanyUserDTO -> {
            Long userId1 = sysCompanyUserDTO.getUserId();
            Long companyId1 = sysCompanyUserDTO.getCompanyId();

            //调用dao层方法,根据userId companyId查询
            List<SysRole> sysRoles = roleMapper.queryRoleByUserIdAndCompanyId(userId1, companyId1);

            List<SysRoleDTO> roleDTOS = BeanHelper.copyWithCollection(sysRoles, SysRoleDTO.class);
            sysCompanyUserDTO.setRoles(roleDTOS);
        });

        return companyUserDTOS;
    }

    /**
     * 获取当前登录用户对应企业的主管理员
     *
     * @return
     */
    @Override
    public SysCompanyUserDTO queryCurrentAdmin() {

        //获取当前用户的企业ID
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //查询主管理员 ROLE_ADMIN_SYS
        SysCompanyUser companyUserAdmin = companyUserMapper.queryCurrentAdminByCompanyId(companyId);

        //封装数据返回
        return BeanHelper.copyProperties(companyUserAdmin, SysCompanyUserDTO.class);
    }

    /**
     * 根据当前登录用户, 获取当前企业员工列表
     *
     * @return
     */
    @Override
    public List<SysCompanyUserDTO> queryCompanyMemberList() {
        //获取当前登录用户的企业ID
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //组装查询条件
        LambdaQueryWrapper<SysCompanyUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(SysCompanyUser::getCompanyId, companyId); //组装企业ID
        userWrapper.eq(SysCompanyUser::getEnable, (short) 1); //组装enable状态

        //查询
        List<SysCompanyUser> companyUsers = companyUserMapper.selectList(userWrapper);

        if (CollectionUtil.isEmpty(companyUsers)) {
            throw new NcException(ResponseEnum.USER_NOT_FOUND);
        }

        //组装数据返回
        List<SysCompanyUserDTO> companyUserDTOS = BeanHelper.copyWithCollection(companyUsers, SysCompanyUserDTO.class);
        return companyUserDTOS;
    }

    /**
     * 根据员工ID查询员工信息
     *
     * @param companyUserId
     * @return
     */
    @Override
    public SysCompanyUserDTO queryByCompanyUserId(Long companyUserId) {
        SysCompanyUser companyUser = companyUserMapper.selectById(companyUserId);
        return BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
    }

    /**
     * 查询当前企业所有的员工 (OrganizationControllerApi 定义过,直接调用也可以)
     *
     * @return
     */
    @Override
    public List<SysCompanyUserDTO> queryAllCompanyUser() {
        //获取企业ID
        Long companyId = CurrentUserHolder.get().getCompanyId();
        //组装查询条件
        LambdaQueryWrapper<SysCompanyUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(SysCompanyUser::getCompanyId, companyId);
        lambdaQueryWrapper.eq(SysCompanyUser::getEnable, (short) 1);

        List<SysCompanyUser> companyUserList = companyUserMapper.selectList(lambdaQueryWrapper);

        return BeanHelper.copyWithCollection(companyUserList, SysCompanyUserDTO.class);
    }

    /**
     * 根据条件分页查询员工列表
     *
     * @param page         页码
     * @param pageSize     页大小
     * @param keyword      关键字
     * @param departmentId 部门ID
     * @return
     */
    @Override
    public PageResult<SysCompanyUserDTO> queryMembers(Integer page, Integer pageSize, String keyword, Long departmentId) {
        //获取当前企业ID
        Long companyId = CurrentUserHolder.get().getCompanyId();

        //1. 组装查询条件
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId, companyId);//企业ID
        wrapper.eq(SysCompanyUser::getEnable, 1); //状态为审核已通过
        //关键字
        if (StrUtil.isNotEmpty(keyword)) { //姓名 , 工号 , 手机号
            wrapper.eq(SysCompanyUser::getUserName, keyword)
                    .or()
                    .eq(SysCompanyUser::getWorkNumber, keyword)
                    .or()
                    .eq(SysCompanyUser::getMobile, keyword);
        }
        //部门ID (有可能是部门ID 也可能是子部门ID)
        List<Long> departmentIds = new ArrayList<>();
        if (departmentId != null && departmentId != 0) { //传递了departmentId
            departmentIds.add(departmentId);

            //递归查询该部门下的子部门ID
            this.queryChildDeparmentIds(departmentIds, departmentId);

            wrapper.in(SysCompanyUser::getDepartmentId, departmentIds);
        }

        //设置排序条件
        wrapper.orderByDesc(SysCompanyUser::getCreateTime);

        //3. 执行查询
        Page<SysCompanyUser> pageObj = new Page<>(page, pageSize);
        pageObj = companyUserMapper.selectPage(pageObj, wrapper);

        //4. 组装返回结果
        List<SysCompanyUser> records = pageObj.getRecords();
        if (CollectionUtil.isNotEmpty(records)) {
            List<SysCompanyUserDTO> userDTOS = BeanHelper.copyWithCollection(records, SysCompanyUserDTO.class);
            //补充员工的所属部门
            userDTOS.stream().forEach(sysCompanyUserDTO -> {
                SysDepartmentDTO departmentDTO = new SysDepartmentDTO();

                departmentDTO.setId(sysCompanyUserDTO.getId());
                departmentDTO.setName(sysCompanyUserDTO.getDepartmentName());
                //将department 设置到 sysCompanyUserDTO中
                sysCompanyUserDTO.setDepartment(departmentDTO);
            });

            return new PageResult<>(pageObj.getTotal(), pageObj.getPages(), userDTOS);
        }

        return null;
    }

    /**
     * 递归! 根据给定的部门ID集合, 查询其下所有的部门ID集合
     *
     * @param departmentIds
     */
    public void queryChildDeparmentIds(List<Long> departmentIds, Long departmentId) {

        LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDepartment::getParentId, departmentId);

        List<SysDepartment> departments = departmentMapper.selectList(wrapper);
        if (CollectionUtil.isNotEmpty(departments)) {
            departments.stream().forEach(sysDepartment -> {
                Long id = sysDepartment.getId();
                departmentIds.add(id);
                //递归调用
                queryChildDeparmentIds(departmentIds, id);
            });
        }
    }

    /**
     * 直接导入数据,解析excel文件
     *
     * @param excelFile
     * @throws IOException
     */
    @Override
    public void importData(MultipartFile excelFile) throws IOException {
        //1. 参数校验
        if (excelFile == null) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //2. 解析Excel文件
        EasyExcel.read(excelFile.getInputStream(),
                ExcelMember.class,
                new ExcelMemberListener(this)) // 直接传入当前对象
                .sheet(0)
                .doRead();
    }

    /**
     * 插入数据到数据库
     *
     * @param memberList
     */
    @Override
    public void parsedData(List<ExcelMember> memberList) {

        if (memberList != null) {
            for (ExcelMember excelMember : memberList) {

                //1. 插入 SysUser用户数据
                SysUser sysUser = new SysUser();

                //1.1 判定系统用户手机号,邮箱是否已经被注册
                int count = userMapper.checkMobileAndEmail(excelMember.getMobile(), excelMember.getEmail());
                if (count != 0) {
                    throw new NcException(ResponseEnum.USER_MOBILE_EMAIL_EXISTS);
                }

                //1.2 判定企业用户工号是否被占用
                int worknumberCount = companyUserMapper.checkWorknumber(excelMember.getWorkNumber());
                if (worknumberCount != 0) {
                    throw new NcException(ResponseEnum.WORK_NUM_EXISTS);
                }

                //1.3 封装系统用户数据,对密码进行加密
                sysUser.setMobile(excelMember.getMobile());
                sysUser.setEmail(excelMember.getEmail());
                sysUser.setUsername(excelMember.getName());
                sysUser.setCreateTime(excelMember.getEntryTime());

                sysUser.setStatus(excelMember.getEnable().equals("可用") ? (short) 1 : (short) 0);
                sysUser.setPassword(new BCryptPasswordEncoder().encode("123456"));
                sysUser.setLastLoginCompanyId(CurrentUserHolder.get().getCompanyId());

                //1.4 保存系统用户
                userMapper.insert(sysUser);

                //2. 插入 CompanyUser员工数据
                SysCompanyUser companyUser = new SysCompanyUser();

                //2.1 组装员工的基本信息
                companyUser.setUserId(sysUser.getId());
                companyUser.setUserName(excelMember.getName());
                companyUser.setMobile(excelMember.getMobile());
                companyUser.setEmail(excelMember.getEmail());
                companyUser.setRemark(excelMember.getDesc()); //备注
                companyUser.setEnable(excelMember.getEnable().equals("可用") ? (short) 1 : (short) 0);
                companyUser.setPost(excelMember.getPosition()); //职位
                companyUser.setCompanyId(CurrentUserHolder.get().getCompanyId()); //企业ID
                companyUser.setCompanyName(CurrentUserHolder.get().getCompanyName());
                companyUser.setOfficeAddress(excelMember.getWorkAddr());
                companyUser.setTimeEntry(excelMember.getEntryTime());
                companyUser.setWorkNumber(excelMember.getWorkNumber()); //工号

                //2.2 组装员工的部门信息
                //根据 部门名称 获取 部门ID
                String departmentName = excelMember.getDepartmentName();
                if (StrUtil.isNotEmpty(departmentName)) {
                    //组装查询条件
                    LambdaQueryWrapper<SysDepartment> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SysDepartment::getCompanyId, CurrentUserHolder.get().getCompanyId()); //企业ID
                    wrapper.eq(SysDepartment::getName, departmentName); //部门名称

                    SysDepartment department = departmentMapper.selectOne(wrapper);
                    if (department != null) {
                        //赋值 部门ID
                        companyUser.setDepartmentId(department.getId());
                        companyUser.setDepartmentName(departmentName);
                    }
                }
                //2.3 保存企业员工
                companyUserMapper.insert(companyUser);

                //2.4 保存员工的角色信息
                String roleName = excelMember.getRoleName();
                if (StrUtil.isNotEmpty(roleName)) {
                    //根据角色名查询角色
                    LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(SysRole::getRoleDesc, roleName); //角色名
                    wrapper.eq(SysRole::getCompanyId, CurrentUserHolder.get().getCompanyId()); //企业ID

                    SysRole role = roleMapper.selectOne(wrapper);
                    if (role != null) {
                        SysCompanyUserRole companyUserRole = new SysCompanyUserRole();
                        companyUserRole.setCompanyId(CurrentUserHolder.get().getCompanyId());
                        companyUserRole.setCompanyUserId(companyUser.getId());
                        companyUserRole.setRoleId(role.getId());

                        companyUserRoleMapper.insert(companyUserRole);
                    }
                }
            }
        }
    }

    /**
     * 根据手机号获取企业员工数据
     * @param mobile
     * @return
     */
    @Override
    public SysCompanyUserDTO findCompanyUserByMobile(String mobile) {
        //参数校验
        if (StrUtil.isEmpty(mobile)) {
            throw new NcException(ResponseEnum.INVALID_PARAM_ERROR);
        }

        //组装条件查询
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.eq(SysCompanyUser::getMobile, mobile);

        //查询
        SysCompanyUser sysCompanyUser = companyUserMapper.selectOne(wrapper);

        //返回数据
        return BeanHelper.copyProperties(sysCompanyUser, SysCompanyUserDTO.class);
    }

    /**
     * 根据部门ID, 查询该部门下的员工数量
     * @param departmentIds
     * @return
     */
    @Override
    public Integer queryUserCountByDepartmentIds(List<Long> departmentIds) {

        //参数校验
        if (CollectionUtil.isEmpty(departmentIds)){
            return 0;
        }

        //遍历部门集合,获取每一个部门下的子部门
        List<Long> depIds = new ArrayList<>();
        depIds.addAll(departmentIds);

        //遍历的是departmentIds,不能是depIds,会出现并发修改异常。集合遍历过程中，不能修改集合长度!!!!!!
        for (Long depId : departmentIds) {
            queryChildDeparmentIds(depIds, depId);
        }

        //去重
        Set<Long> ids = new HashSet<>(depIds);

        //组装条件查询用户数量
        LambdaQueryWrapper<SysCompanyUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysCompanyUser::getCompanyId,CurrentUserHolder.get().getCompanyId());
        wrapper.in(SysCompanyUser::getDepartmentId , ids);

        Integer count = companyUserMapper.selectCount(wrapper);
        return count;
    }

    /**
     * 根据企业ID查询企业的主管理员信息
     * @param companyId
     * @return
     */
    @Override
    public SysCompanyUserDTO queryAdminByCompanyId(Long companyId) {
        SysCompanyUser companyUser = companyUserMapper.queryCurrentAdminByCompanyId(companyId);
        return BeanHelper.copyProperties(companyUser, SysCompanyUserDTO.class);
    }
}